<template>
  <div style="width:100%;overflow:hidden;">
    <div id="container"></div>
    <div id="minimap"></div>
  </div>
</template>

<script>
import axios from 'axios'
import {mapState} from 'vuex'
import {chainData} from '@/utils/mock/chain'
import {shuangjibanData} from '@/utils/mock/shuangjiban'
export default {
  props: {
    data: {
      type: Object
    },
    needRender: {
      type: Boolean
    }
  },
  data() {
    return {
      dblData: {},
      cancel: null,
      scrollWidth: 0,
      scrollHeight: 0,
      fixWidth: 0,
      toggleCombo: false,
      graph: null,
      colors: ['#7bcac0', '#405bd9'],
      level: 2, // 层级
      centerNodeWidth: 100,
      centerNodeHeight: 32,
      leafNodeWidth: 120,
      leafNodeHeight: 32,
      leafNodeChildHeight: 27,
      // 中心节点
      centerNode: {},
      // 当前中心节点子节点
      curCenterChildNode: {},
      // 中心节点组
      centerNodes: [],
      // 左侧叶子节点连线
      leftLeafEdges: [],
      // 左侧叶子节点与中心子节点的连线
      leftCenterNodeEdges: [],
      // 右侧叶子节点连线
      rightLeafEdges : [],
      // 右侧叶子节点与中心子节点的连线
      rightCenterNodeEdges: [],
    }
  },
  computed:{
    ...mapState(['levelName','levelCode']),
  },
  methods: {
    init() {
      this.scrollWidth = document.getElementById('container').scrollWidth
      this.scrollHeight = document.getElementById('container').scrollHeight || 500
      this.fixWidth = JSON.parse(JSON.stringify(this.scrollWidth)) > 1400 ? 1400 : this.scrollWidth
      
      // this.setNode()

      // this.renderData()
      this.renderData('双极板', shuangjibanData)
      
      // this.renderData('双极板', shuangjibanData)

    },
    
    // 自定义
    setNode(name) {
      // 中心节点
      G6.registerNode('centerNode', {
        draw(cfg, group) {
          let fillColor = name === '双极板' ? '#ffc009' : '#524CAB'
          cfg.padding = cfg.padding || [6, 6, 6, 6]
          const style = cfg.style
          const keyShape = group.addShape('rect', {
            // attrs: {
            //   ...style,
            //   fill: fillColor,
            //   radius: [4],
            // },
            attrs: {
              ...style,
              radius: [4],
              lineWidth: 4,
              cursor: 'pointer'
            },
            // name: 'center-key-shape',
            draggable: true
          })

          // const content = cfg.label.length > 10 ? cfg.label.replace(/(.{10})/g, '$1\n') : cfg.label
          const content = cfg.label && cfg.label.length > 7 ? cfg.label.substr(0, 5) + '...' : cfg.label
          const text = group.addShape('text', {
            attrs: {
              textAlign: 'center',
              textBaseline: 'top',
              text: content,
              fill: '#fff',
              x: 50,
              y: 0,
              fontSize: 12,
              textAlign: 'center',
              lineHeight: 14,
              cursor: 'pointer'
            },
            name: 'center-text-shape',
            draggable: true
          })

          const bbox = text.getBBox()
          keyShape.attr({
            // x: bbox.minX - 10,
            y: bbox.minY - 11,
            // width: bbox.width + 20,
            width: 100,
            height: bbox.height + 20,
          })

          let tagText = group.addShape('text', {
            attrs: {
              textAlign: 'center',
              textBaseline: 'top',
              // text: (cfg.compCount && cfg.compCount > 0) ? cfg.compCount : '招',
              text: (cfg.compCount && cfg.compCount > 0) ? cfg.compCount : '',
              fill: '#fff',
              fontSize: 10,
              fontVariant: 'small-caps',
              textAlign: 'center',
              lineHeight: 14,
              cursor: 'pointer'
            }
          })

          
          let leftFillColor = name === '双极板' ? '#ffc009' : '#3CC4B6'
          let leftStrokeColor = name === '双极板' ? '#ffc009' : '#c5e8e3'
          // 左侧叶子节点
          keyShape.attr({
            // fill: '#3CC4B6',
            fill: leftFillColor,
            stroke: leftStrokeColor,
          })
          if (cfg.compCount && cfg.compCount > 0) {
            // tagCircle.attr({
            //   x: 120,
            //   y: 5,
            //   fill: '#3CC4B6'
            // })
            tagText.attr({
              x: 100,
              y: 0,
              textAlign: 'center'
            })
          } else {
            // tagCircle.attr({
            //   x: 0,
            //   y: 5,
            //   fill: '#3CC4B6'
            // })
            tagText.attr({
              x: 0,
              y: 0
            })
          }


          // if (cfg.nodeType && cfg.nodeType === 'centerChildNode') {
          //   keyShape.attr({
          //     fill: '#807de2'
          //   })
          //   // tagCircle.attr({
          //   //   fill: '#807de2'
          //   // })
          // }


          // tagText.attr({
          //   x: 100,
          //   y: 0,
          //   textAlign: cfg.compCount > 100 ? 'end' : 'center'
          // })

          return keyShape
        },
        // 响应状态变化
        setState(name, value, item) {
          const group = item.getContainer()
          const shape = group.get('children')[0] // 顺序根据 draw 时确定
          // const tagCircle = group.get('children')[2]
          if (name === 'selected') {
            if (value) {
              shape.attr('fill', '#524CAB')
              // tagCircle.attr('fill', '#524CAB')
            } else {
              shape.attr('fill', '#807de2')
              // tagCircle.attr('fill', '#807de2')
            }
          }
        }
      }, 'single-node')
      // 中心combo
      G6.registerCombo('centerCombo', {
        drawShape: function(cfg, group) {
          const self = this
          // 获取配置中的 Combo 内边距
          cfg.padding = cfg.padding || [6, 6, 6, 6]
          // cfg.padding = [0, 0, 0, 0]
          // 获取样式配置，style.width 与 style.height 对应 rect Combo 位置说明图中的 width 与 height
          const style = self.getShapeStyle(cfg)
          let fillColor = name === '双极板' ? '#ffc009' : '#524CAB'
          const keyShape = group.addShape('rect', {
            attrs: {
              ...style,
              x: -style.width / 2 - (cfg.padding[3] - cfg.padding[1]) / 2,
              y: -style.height / 2 - (cfg.padding[0] - cfg.padding[2]) / 2,
              width: style.width,
              height: style.height,
              fill: '#fff',
              stroke: fillColor,
              radius: [4]
            },
            name: 'key-combo',
            draggable: true
          })

          return keyShape
        },
        // 响应状态变化
        setState(name, value, item) {
          const group = item.getContainer()
          const shape = group.get('children')[0]; // 顺序根据 draw 时确定
          if (name === 'selected') {
            if (value) {
              shape.attr('fill', '#524CAB');
            } else {
              shape.attr('fill', '#807de2');
            }
          }
        }
      }, 'rect')
      // 叶子节点
      G6.registerNode('leafNode', {
        draw(cfg, group) {
          const style = cfg.style
          const keyShape = group.addShape('rect', {
            attrs: {
              ...style,
              radius: [4],
              lineWidth: 4,
              cursor: 'pointer'
            },
            name: 'leaf-key-shape',
            draggable: true
          })

          // const content = cfg.label.length > 10 ? cfg.label.replace(/(.{10})/g, '$1\n') : cfg.label
          const content = cfg.label && cfg.label.length > 7 ? cfg.label.substr(0, 5) + '...' : cfg.label
          const text = group.addShape('text', {
            attrs: {
              textAlign: 'center',
              textBaseline: 'top',
              text: content,
              fill: '#fff',
              x: 60,
              y: 0,
              fontSize: 12,
              textAlign: 'center',
              lineHeight: 14,
              cursor: 'pointer'
            },
            name: 'center-text-shape',
            draggable: true
          })

          const bbox = text.getBBox()
          keyShape.attr({
            // x: bbox.minX - 10,
            y: bbox.minY - 11,
            // width: bbox.width + 20,
            width: 120,
            height: bbox.height + 20,
          })

          // 展示产业下公司数量，如果没有则展示“招”字
          // let tagCircle= group.addShape('circle', {
          //   attrs: {
          //     r: 10,
          //     cursor: 'pointer'
          //   }
          // })
          let tagText = group.addShape('text', {
            attrs: {
              textAlign: 'center',
              textBaseline: 'top',
              // text: (cfg.compCount && cfg.compCount > 0) ? cfg.compCount : '招',
              text: (cfg.compCount && cfg.compCount > 0) ? cfg.compCount : '',
              fill: '#fff',
              fontSize: 10,
              fontVariant: 'small-caps',
              textAlign: 'center',
              lineHeight: 14,
              cursor: 'pointer'
            }
          })

          // 左侧叶子子节点和右侧叶子子节点公共样式
          if (cfg.nodeType === 'left-child' || cfg.nodeType === 'right-child') {
            keyShape.attr({
              y: bbox.minY - 9,
              height: bbox.height + 15
            })
            text.attr({
              fontSize: 11
            })
          }
          
          let leftFillColor = name === '双极板' ? '#ccc' : '#3CC4B6'
          let rightFillColor = name === '双极板' ? '#ccc' : '#405bd9'
          let leftStrokeColor = name === '双极板' ? '#ccc' : '#c5e8e3'
          let rightStrokeColor = name === '双极板' ? '#ccc' : '#B4C1F5'

          
          if (cfg.label === '石墨材料加工') {
            leftFillColor = '#ffc009'
            rightFillColor = '#ffc009'
            leftStrokeColor = '#ffc009'
            rightStrokeColor = '#ffc009'
          }

          // 左侧叶子节点
          keyShape.attr({
            // fill: '#3CC4B6',
            fill: leftFillColor,
            stroke: leftStrokeColor,
          })
          if (cfg.compCount && cfg.compCount > 0) {
            // tagCircle.attr({
            //   x: 120,
            //   y: 5,
            //   fill: '#3CC4B6'
            // })
            tagText.attr({
              x: 120,
              y: 0,
              textAlign: cfg.compCount > 100 ? 'end' : 'center'
            })
          } else {
            // tagCircle.attr({
            //   x: 0,
            //   y: 5,
            //   fill: '#3CC4B6'
            // })
            tagText.attr({
              x: 0,
              y: 0
            })
          }

          // 左侧叶子子节点
          if (cfg.nodeType === 'left-child') {
            keyShape.attr({
              fill: leftFillColor,
              stroke: '#c5e8e3',
              opacity: .8,
            })
            // tagCircle.attr({
            //   y: 5,
            //   fill: '#3CC4B6',
            //   opacity: .8
            // })
            if (cfg.compCount && cfg.compCount > 0) {
              // tagCircle.attr({
              //   x: 120,
              // })
              tagText.attr({
                x: 120,
                y: 0,
                textAlign: cfg.compCount > 100 ? 'start' : 'center'
              })
            } else {
              // tagCircle.attr({
              //   x: 0,
              // })
              tagText.attr({
                x: 0,
                y: 0
              })
            }
          }

          // 右侧叶子节点
          if (cfg.nodeType === 'right' && cfg.label === '双极板') {
            keyShape.attr({
              fill: rightFillColor,
              stroke: rightStrokeColor,
            })
            // tagCircle.attr({
            //   x: 0,
            //   y: 5,
            //   fill: rightFillColor
            // })
            if (cfg.compCount && cfg.compCount > 0) {
              tagText.attr({
                x: 0,
                y: 0,
                textAlign: cfg.compCount > 100 ? 'start' : 'center'
              })
            } else {
              tagText.attr({
                x: 0,
                y: 0
              })
            }
          }

          // 右侧叶子子节点
          if (cfg.nodeType === 'right-child') {
            keyShape.attr({
              fill: rightFillColor,
              stroke: rightStrokeColor,
              opacity: .8,
            })
            // tagCircle.attr({
            //   x: 0,
            //   y: 5,
            //   fill: rightFillColor,
            //   opacity: .8
            // })
            if (cfg.compCount && cfg.compCount > 0) {
              tagText.attr({
                x: 0,
                y: 0,
                textAlign: cfg.compCount > 100 ? 'start' : 'center'
              })
            } else {
              tagText.attr({
                x: 0,
                y: 0
              })
            }
          }

          // 左侧多级节点
          if (cfg.nodeType === 'left-layer') {
            keyShape.attr({
              fill: '#cdc5f7',
              stroke: '#cdc5f7',
            })
            if (cfg.compCount && cfg.compCount > 0) {
              // tagCircle.attr({
              //   x: 120,
              //   y: 5,
              //   fill: '#cdc5f7'
              // })
              tagText.attr({
                x: 120,
                y: 0,
                textAlign: cfg.compCount > 100 ? 'end' : 'center'
              })
            } else {
              // tagCircle.attr({
              //   x: 0,
              //   y: 5,
              //   fill: '#cdc5f7'
              // })
              tagText.attr({
                x: 0,
                y: 0,
              })
            }
          }

          // 右侧多级节点
          if (cfg.nodeType === 'right-layer') {
            keyShape.attr({
              fill: '#4587cb',
              stroke: '#4587cb',
            })
            // tagCircle.attr({
            //   x: 0,
            //   y: 5,
            //   fill: '#4587cb'
            // })
            if (cfg.compCount && cfg.compCount > 0) {
              tagText.attr({
                x: 0,
                y: 0,
                textAlign: cfg.compCount > 100 ? 'start' : 'center'
              })
            } else {
              tagText.attr({
                x: 0,
                y: 0,
              })
            }
            
          }

          return keyShape
        },
        // 动画
        afterDraw(cfg, group) {
          if (cfg.nodeType && cfg.nodeType.indexOf('child') > -1) {
            // 获取该节点上的第一个图形
            let children = group.get('children')
            let model = group.get('item').getModel()
            
            children.forEach((v, i) => {
              if (i !== 1) {
                v.animate(
                  (ratio) => {
                    return {
                      x: model.nodeType.indexOf('left') > -1 ? 140 * ratio : -150 * ratio,
                    }
                  },
                  {
                    repeat: false,
                    duration: 200,
                    easing: 'easeQuadInOut',
                  },
                )
              } else {
                // center-text
                v.animate(
                  (ratio) => {
                    return {
                      x: model.nodeType.indexOf('left') > -1 ? 200 * ratio : -90 * ratio,
                    }
                  },
                  {
                    repeat: false,
                    duration: 200,
                    easing: 'easeQuadInOut',
                  },
                )
              }
              
            })
          }
        },
        // 响应状态变化
        setState(name, value, item) {
          const group = item.getContainer()
          const children = group.get('children'); // 顺序根据 draw 时确定
          // 0： keyShape
          // 1： center-text
          // 2 和 3： 左/右侧上的公司数量 圆圈和内容
          const width = 120
          const distance = 20
          let model = group.get('item').getModel()
          if (name === 'selected') {
            if (value) {
              if (model.nodeType.indexOf('left') > -1) { // 左侧
                children.forEach((v, i) => {
                  if (i === 1) {
                    v.attr({
                      width: width - distance,
                      x: (width - distance) / 2
                    })
                  } else if (i === 2) {
                    v.attr({
                      opacity: '.4',
                      x: width - distance
                    })
                  } else if (i === 3) {
                    v.attr({
                      x: width - distance
                    })
                  } else {
                    v.attr({
                      opacity: '.4',
                      width: width - distance
                    })
                  }
                })
              } else { // 右侧
                children.forEach((v, i) => {
                  if (i === 1) {
                    v.attr({
                      width: width - distance,
                      x: (width) / 2 + 10
                    })
                  } else if (i === 2) {
                    v.attr({
                      opacity: '.4',
                      x: distance
                    })
                  } else if (i === 3) {
                    v.attr({
                      x: distance
                    })
                  } else {
                    v.attr({
                      opacity: '.4',
                      width: width - distance,
                      x: distance
                    })
                  }
                })
              }
              
            } else {
              if (model.nodeType.indexOf('left') > -1) { // 左侧
                children.forEach((v, i) => {
                  if (i === 1) {
                    v.attr({
                      width: width,
                      x: (width) / 2,
                    })
                  } else if (i === 2 || i === 3) {
                    v.attr({
                      opacity: '1',
                      x: width,
                    })
                  } else {
                    v.attr({
                      opacity: '1',
                      width: width,
                    })
                  }
                  
                })
              } else {  // 右侧
                children.forEach((v, i) => {
                  if (i === 1) {
                    v.attr({
                      x: (width) / 2
                    })
                  } else if (i === 2 || i === 3) {
                    v.attr({
                      x: 0
                    })
                  } else {
                    v.attr({
                      opacity: '1',
                      width: width,
                      x: 0
                    })
                  }
                })
              }
              
            }
          }
        },
        // 锚点
        getAnchorPoints(cfg) {
          if (cfg.nodeType.indexOf('child') > -1) {
            let arr = []
            if (cfg.nodeType.indexOf('left') > -1) {
              arr.push([1, 0.5])
            } else {
              arr.push([0, 0.5])
            }
            return arr
          } else {
            return [
              [1, 0.5],
              [0, 0.5]
            ]
          }
        }
      }, 'rect')
      // 连线
      G6.registerEdge('custom-line', {
        afterDraw(cfg, group) {
        }
      }, 'cubic-horizontal')

      if (this.needRender) {
        // this.resetChart(this.data)
      }
    },
    renderData(name, data2) {
      if (this.graph) {
        this.graph.destroy()
      }
      this.setNode(name)
      // 中心节点子节点
      let data = {
        name: name, //'全氢能产业链',
        code: '0',
        compCount: 0,
        hasCompany: false
      }
      let data1 = []
      let centerNodes = []
      let x = this.scrollWidth / 2 - this.centerNodeWidth / 2
      let y = this.scrollHeight / 2 - this.centerNodeHeight / 2
      data1.forEach(v => {
        centerNodes.push({
          id: v.code,
          label: v.name,
          code: v.code,
          x,
          y,
          size: [this.centerNodeWidth, this.centerNodeHeight],
          type: 'centerNode',
          nodeType: 'centerChildNode',
          // comboId: 'centerCombo',
          compCount: v.compCount || 0
        })
      })
      // 中心节点
      let obj = {
        id: data.code,
        label: data.name,
        code: data.code,
        x,
        y,
        size: [this.centerNodeWidth, this.centerNodeHeight],
        type: 'centerNode',
        // comboId: 'centerCombo',
        compCount: data.compCount || 0
      }
      centerNodes.push(obj)
      this.centerNode = obj
      this.centerNodes = centerNodes

      // 动态多级上下游产业
      // let data2 = chainData || {}
      if (Object.keys(data2).length > 0) {
        let leftLeafNodes = []
        let rightLeafNodes = []
        let getLeafNodes = (d, type, nodeType, leafNodes) => {
          let nodes = []
          // 子集数据
          let childrenData = {}
          childrenData[type] = []
          d[type].forEach(v => {
            if (v.code !== (this.centerNodes && this.centerNodes[0] && this.centerNodes[0].code)) {
              let obj = {
                id: v.code,
                label: v.name,
                code: v.code,
                type: 'leafNode',
                nodeType: nodeType,
                compCount: v.compCount || 0,
                parent: v.parent || [],
                selected: false, // 当前是否选中该节点
                lowerIndustry: [], // 当前节点下级产品
                companyArr: v.companyArr || []
              }
              nodes.push(obj)
              if (v[type] && v[type].length > 0) {
                v[type].forEach(b => {
                  if (!b['parent']) {
                    b['parent'] = []
                  }
                  b['parent'].push(obj)
                })
                childrenData[type].push(...v[type])
              }
            }
          })
          if (leafNodes) {
            leafNodes.push(nodes)
          }
          
          // 如果有children数据，继续迭代
          if (childrenData[type].length > 0) {
            // 去重
            let newChildrenData = {}
            newChildrenData[type] = this.distinct(childrenData[type])
            getLeafNodes(newChildrenData, type, nodeType, leafNodes)
          }
        }
        getLeafNodes(data2, 'up', 'left', leftLeafNodes)
        getLeafNodes(data2, 'down', 'right', rightLeafNodes)
        
        // 计算叶子节点位置
        this.leftLeafNodes = this.computedLeafPos(leftLeafNodes, 'left')
        this.rightLeafNodes = this.computedLeafPos(rightLeafNodes, 'right')

        // 叶子节点连线
        this.leftLeafEdges = this.getLeafEdges(this.leftLeafNodes, 'left')
        this.rightLeafEdges = this.getLeafEdges(this.rightLeafNodes, 'right')

        this.renderChart()
      }
    },
    // 获取数据
    getAllData(data) {
      // this.getInitNodeData(data)
    },
    // 计算多级叶子节点位置
    computedLeafPos(leafNodes, type) {
      let centerPosX = this.scrollWidth / 2 - this.centerNodeWidth / 2  // 中心位置
      if (type === 'left') { // 左侧
        leafNodes.forEach((v, i) => {
          let x = centerPosX - (this.leafNodeWidth * 1.5) * (Number(i) + 1)
          // let space = v.length < 3 ? 30 :
          //   v.length < 6 ? 20 : 15
          let space = 10
          let nodesHeight = this.leafNodeHeight * v.length + space * (v.length - 1)
          let startY = this.scrollHeight / 2 - nodesHeight / 2
          v.forEach((b, j) => {
            b.x = x
            b.y = startY + (this.leafNodeHeight + space) * j
          })
        })
      } else if (type === 'right') { // 右侧
        leafNodes.forEach((v, i) => {
          let x = (centerPosX - 31) + (this.leafNodeWidth * 1.5) * (Number(i) + 1)
          // let space = v.length < 3 ? 30 :
          //   v.length < 6 ? 20 : 15
          let space = 10
          let nodesHeight = this.leafNodeHeight * v.length + space * (v.length - 1)
          let startY = this.scrollHeight / 2 - nodesHeight / 2
          v.forEach((b, j) => {
            b.x = x
            b.y = startY + (this.leafNodeHeight + space) * j
          })
        })
      }

      return leafNodes
    },
    // 计算叶子节点产品x,y位置
    computedLeafChildPos(model) {
      let x = model.x
      let y = model.y
      let spaceX = 14 // 横向间距
      let leafNodes = []

      if (model.nodeType === 'left') {
        x += spaceX
        leafNodes = this.leftLeafNodes
      } else {
        x -= spaceX
        leafNodes = this.rightLeafNodes
      }

      y = y < this.scrollHeight / 1.8 ? 
        y : y - (this.leafNodeChildHeight * (model['lowerIndustry'].length - 1) / 2)
      
      let comparedCodes = []
      model['lowerIndustry'].forEach((v, i) => {
        v.x = x
        v.y = y + (this.leafNodeChildHeight) * i
        comparedCodes.push(v.code)
        this.graph.addItem('node', v)
      })

      if (model.parent.length > 0) {
        model.parent.forEach(v => {
          this.getLeafChildNodeRelation(v, comparedCodes, model.nodeType)
        })
      } else {
        // 如果是1级，则获取叶子节点子节点与中心节点组的关系连线
        let isHas = leafNodes[0].filter(item => item.id === model.id)
        if (isHas.length > 0) {
          // 如果中心节点子节点被选中
          if (Object.keys(this.curCenterChildNode).length > 0) {
            let curCenterChildNodeModel = this.curCenterChildNode.getModel()
            let edges = this.graph.getEdges()
            let needRemoveEdges = []
            edges.forEach(v => {
              let mod = v.getModel()
              leafNodes[0].forEach(b => {
                if (mod.source === b.code && mod.target === curCenterChildNodeModel.code) {
                  needRemoveEdges.push(v)
                }
              })
            })
            needRemoveEdges.forEach(v => {
              this.graph.removeItem(v)
            })
          }

          this.centerNodes.forEach(v => {
            this.getLeafChildNodeRelation(v, comparedCodes, model.nodeType)
          })
        }
      }

      // 节点位置发生变化时，刷新所有节点位置，并重计算边的位置
      this.refreshPos()

      // 重绘
      this.toPaint()

    },
    // 获取叶子节点产品与上级的连线
    getLeafChildNodeRelation(v, comparedCodes, type) {
      this.$post(this.$Url.industrial.getIndustryRelation, {
        code: v.code,
        cityCode: this.levelCode,
        comparedCodes
      }).then(res => {
        // 1是有关系，0是没关系
        let data = res.data
        if (data) {
          let keys = Object.keys(data)
          let values = Object.values(data)
          let edges = []
          values.forEach((b, j) => {
            if (b === 1) {
              let edge = {
                source: keys[j],
                target: v.code,
                color: this.colors[0] // type === 'left' ? this.colors[0] : this.colors[1],
              }
              
              if (type === 'left') {
                edge['edgeType'] = 'left'
                edge['style'] = {
                  opacity: 1
                }
              } else if (type === 'right') {
                edge['edgeType'] = 'right'
                edge['style'] = {
                  opacity: 1
                }
              }

              this.graph.addItem('edge', edge)
            }
          })

        }
      })
    },
    // 获取叶子节点连线
    getLeafEdges(leafNodes, type) {
      let leafEdges = []
      leafNodes.forEach((v, i) => {
        let edge = {}
        if (i === 0) {
          v.forEach(b => {
            edge = {
              source: b.id,
              target: '0',
              color: this.colors[0] // type === 'left' ? this.colors[0] : this.colors[1]
            }
            leafEdges.push(edge)
          })
        } else {
          v.forEach(b => {
            b.parent.forEach(n => {
              edge = {
                source: b.id,
                target: n.id,
                color: this.colors[0] // type === 'left' ? this.colors[0] : this.colors[1]
              }
              leafEdges.push(edge)
            })
          })
        }
        
      })
      return leafEdges
    },
    // 获取叶子节点产品
    getLeafChildNodes(model, func) {
      let ths = this
      // 中止请求
      if (this.cancel) {
        this.cancel()
      }
      
      let nodes = []
      let edges = []
      if (model.nodeType === 'left') {
        nodes = this.leftLeafNodes
        edges = this.leftLeafEdges
      } else {
        nodes = this.rightLeafNodes
        edges = this.rightLeafEdges
      }
      /*
      ** 找到当前点击的节点所在的节点组和连线
      */
      // 找到当前点击的节点所在的节点组
      let index = 0
      outer: for (let i = 0; i < nodes.length; i++) {
        for (let j = 0; j < nodes[i].length; j++) {
          if (nodes[i][j].id === model.id) {
            index = i
            break outer
          }
        }
      }
      let cnodes = nodes[index]

      // 清除叶子节点产品节点
      cnodes.forEach(v => {
        v['lowerIndustry'].forEach(b => {
          let node = this.graph.findById(b.id)
          this.graph.remove(node)
        })
      })

      // 找到当前点击的节点所在节点组的连线
      let cedges = []
      cnodes.forEach(v => {
        let arr = edges.filter(item => item.source === v.id)
        if (arr.length > 0) {
          arr.forEach(b => {
            let edge = this.graph.findById(b.id)
            cedges.push(edge)
          })
        }
      })

      // 如果再次点击了当前选中的节点
      if (model['selected']) {
        // 重置叶子节点连线样式
        if (!(index === 0 && Object.keys(this.curCenterChildNode).length > 0)) {
          cedges.forEach(v => {
            this.graph.updateItem(v, {
              style: {
                opacity: '1'
              }
            })
          })
        }
        
        model['selected'] = false
        this.leafSetItemState(model, cnodes, false)
        this.layerLeafEdgesStyle(model, nodes, edges, index, false)
        return
      } else {
        cnodes.forEach(v => {
          let node = this.graph.findById(v.id)
          let model = node.getModel()
          model['selected'] = false
        })
        this.leafSetItemState(model, cnodes, true)
        this.layerLeafEdgesStyle(model, nodes, edges, index, true)
        model['selected'] = true
      }

      // 获取叶子节点产品
      this.$get(this.$Url.industrial.getLowerIndustryAndCompInfoByCode, {
        code: model.code,
        cityCode: this.levelCode
      }, new axios.CancelToken(function executor(c) {
        ths.cancel = c
      })).then(res => {
        let data = res.data
        let newNodes = []
        let allNodes = this.graph.getNodes()
        // 节点去重
        data.forEach(v => {
          let isHas = allNodes.filter(item => item.getModel().code === v.code)
          if (isHas.length <= 0) {
            let obj = {
              ...v,
              id: v.code,
              label: v.name,
              type: 'leafNode',
              nodeType: `${model.nodeType}-child`
            }
            newNodes.push(obj)
          }
        })
        // 如果该节点有产品
        if (newNodes.length > 0) {
          model['lowerIndustry'] = newNodes
          // 重置叶子节点连线样式
          this.changeLeafEdgesStyle(cedges, {
            style: {
              opacity: '.2'
            }
          })
        } else {
          // 重置叶子节点连线样式
          cedges.forEach(v => {
            this.graph.updateItem(v, {
              style: {
                opacity: '1'
              }
            })
          })
        }

        func && func(model)
      })
    },
    // 重置叶子节点下级连线样式
    layerLeafEdgesStyle(model, nodes, edges, index, isNeedHigh) {
      // 当前节点下级
      let prevNodes = nodes[index + 1]
      // 当前节点上级
      let nextNodes = nodes[index - 1]

      // 如果节点下级存在，判断是否有选中节点
      if (prevNodes) {
        let isSelected = prevNodes.filter(item => item.selected === true)
        if (isSelected.length > 0) {
          return
        }

        let cedges = []
        prevNodes.forEach(v => {
          let arr = edges.filter(item => item.source === v.id)
          if (arr.length > 0) {
            arr.forEach(b => {
              let edge = this.graph.findById(b.id)
              cedges.push(edge)
            })
          }
        })
        
        if (isNeedHigh) { // 需要高亮
          cedges.forEach(edge => {
            this.graph.updateItem(edge, {
              style: {
                opacity: '.2'
              }
            })
          })
          edges.forEach(v => {
            if (v.target === model.id) {
              let edge = this.graph.findById(v.id)
              this.graph.updateItem(edge, {
                style: {
                  opacity: '1'
                }
              })
            }
          })
        } else { // 不需要高亮
          // 如果当前节点靠近中心节点，则判断是否与中心节点有相关逻辑
          if (index === 0 && Object.keys(this.curCenterChildNode).length > 0) {
            let curCenterChildNodeModel = this.curCenterChildNode.getModel()
            let cnodes = nodes[index]
            let comparedCodes = []
            cnodes.forEach(v => {
              comparedCodes.push(v.code)
            })
            this.getLeafChildNodeRelation(curCenterChildNodeModel, comparedCodes, model.nodeType)
          }
          
          cedges.forEach(edge => {
            this.graph.updateItem(edge, {
              style: {
                opacity: '1'
              }
            })
          })
        }
      }
      // 如果当前节点上级有展开的节点，那么收起时高亮上级节点的连线
      if (nextNodes) {
        if (!isNeedHigh) { // 不需要高亮时
          let isSelected = nextNodes.filter(item => item.selected === true)
          if (isSelected.length > 0) {
            let cedges = []
            nextNodes.forEach(v => {
              let arr = edges.filter(item => item.target === v.id)
              if (arr.length > 0) {
                arr.forEach(b => {
                  cedges.push(b)
                })
              }
            })

            cedges.forEach(v => {
              let edge = this.graph.findById(v.id)
              if (v.target === isSelected[0].id) {
                this.graph.updateItem(edge, {
                  style: {
                    opacity: '1'
                  }
                })
              } else {
                this.graph.updateItem(edge, {
                  style: {
                    opacity: '.2'
                  }
                })
              }
            })

          }
        }
        
      }
    },
    // 叶子节点点击样式切换
    leafSetItemState(model, cnodes, isNeedHigh) {
      if (isNeedHigh) { // 需要高亮
        cnodes.forEach(v => {
          let node = this.graph.findById(v.id)
          if (v.id === model.id) {
            this.graph.setItemState(node, 'selected', false)
          } else {
            this.graph.setItemState(node, 'selected', true)
          }
        })
      } else {
        cnodes.forEach(v => {
          let node = this.graph.findById(v.id)
          this.graph.setItemState(node, 'selected', false)
        })
      }
      // 节点位置发生变化时，刷新所有节点位置，并重计算边的位置
      this.graph.refreshPositions()
    },
    // 重置叶子节点连线样式
    changeLeafEdgesStyle(edges, style) {
      edges.forEach(edge => {
        this.graph.updateItem(edge, {
          ...style
        })
      })
    },
    // 
    renderChart() {
      // 左侧所有叶子节点
      let leftLeafNodes = []
      this.leftLeafNodes.forEach(v => {
        leftLeafNodes.push(...v)
      })
      // 右侧所有叶子节点
      let rightLeafNodes = []
      this.rightLeafNodes.forEach(v => {
        rightLeafNodes.push(...v)
      })

      // 左侧所有叶子节点连线
      // let leftLeafEdges = []
      // this.leftLeafEdges.forEach(v => {
      //   leftLeafEdges.push(...v)
      // })

      // 右侧所有叶子节点连线
      // let rightLeafEdges = []
      // this.rightLeafEdges.forEach(v => {
      //   rightLeafEdges.push(...v)
      // })

      let data = {
        nodes: [
          ...this.centerNodes,
          ...leftLeafNodes,
          ...rightLeafNodes
        ],
        edges: [
          ...this.leftLeafEdges,
          ...this.rightLeafEdges
          // ...this.leafEdges,
          // ...this.leftLeafUpEdges,
          // ...this.rightLeafDownEdges
        ],
        // combos: [
        //   {
        //     id: 'centerCombo',
        //   },
        // ]
      }

      // 缩略图
      const minimap = new G6.Minimap({
        container: 'minimap',
        className: 'minimap',
        type: 'delegate',
        size: [this.scrollWidth, 100]
      })

      

      this.graph = new G6.Graph({
        container: 'container',
        width: this.scrollWidth,
        height: this.scrollHeight,
        groupByTypes: false,
        modes: {
          default: ['drag-canvas', 'zoom-canvas',
            {
              type: 'tooltip',
              offsetX: -20,
              offsetY: -20,
              formatText(model) {
                let text = model.label
                return text
              },
            },
          ]
        },
        plugins: [minimap],
        // defaultCombo: {
        //   type: 'centerCombo'
        // },
        defaultEdge: {
          type: 'cubic-horizontal',
          // curveOffset: [20, 40],
          // curvePosition: [0.3, 0.3]
          curvePosition: [0.5, 0.51]
        },
        animate: true
      })
      this.graph.read(data)
      this.graph.fitCenter()

      // 节点点击事件
      this.graph.on('node:click', (e) => {
        let {item, target} = e
        let model = item.getModel()
        let nodeType = model.nodeType
        let code = model.code

        this.curSelectedNode = model
        // if (model.label === '双极板') {
        //   if (model.id === '0') {
        //     this.renderData('全氢能产业链', chainData)
        //   } else {
        //     this.renderData('双极板', shuangjibanData)
        //   }
          
        // }
        this.$emit('curSelectedNode', this.curSelectedNode)

      })

    },
    // 中心节点点击事件
    centerNodeFunc(code) {
      if (code === this.centerNode.code) {
        this.toggleComboFunc()
      } else {
        // 中心节点子节点点击相关连线
        this.centerChildNodeEdges(code, 'left')
        this.centerChildNodeEdges(code, 'right')
        // 中心节点子节点点击展示样式
        this.centerChildNodeStyle(code)
      }
    },
    // 中心节点子节点点击相关连线
    centerChildNodeEdges(code, type) {
      let node = this.graph.findById(code)

      let curCenterChildNodeModel = {}
      if (Object.keys(this.curCenterChildNode).length > 0) {
        curCenterChildNodeModel = this.curCenterChildNode.getModel()
      }

      let centerNodeEdges = []
      let leafNodes = []

      if (type === 'left') { // 左侧
        leafNodes = this.leftLeafNodes[0]
      } else { // 右侧
        leafNodes = this.rightLeafNodes[0]
      }

      if (code !== curCenterChildNodeModel.code) {

        let isSelected = leafNodes.filter(item => item.selected === true)
        if (isSelected.length > 0) {
          leafNodes = isSelected[0]['lowerIndustry']
          // 先移除之前的连线
          let edges = this.graph.getEdges()
          let cedges = []
          edges.forEach(v => {
            let model = v.getModel()
            leafNodes.forEach(b => {
              if (model.source === b.code) {
                cedges.push(v)
              }
            })
          })
          cedges.forEach(v => {
            this.graph.removeItem(v)
          })
        }

        // 
        let comparedCodes = []
        leafNodes.forEach(v => {
          comparedCodes.push(v.code)
        })

        this.$post(this.$Url.industrial.getIndustryRelation, {
          code: code,
          cityCode: this.levelCode,
          comparedCodes
        }).then(res => {
          // 1是有关系，0是没关系
          let data = res.data
          if (data) {
            let keys = Object.keys(data)
            let values = Object.values(data)
            values.forEach((b, j) => {
              if (b === 1) {
                let edge = {
                  source: keys[j],
                  target: code,
                  color: this.colors[0] // type === 'left' ? this.colors[0] : this.colors[1],
                }
                
                if (type === 'left') {
                  edge['edgeType'] = 'left'
                  edge['style'] = {
                    opacity: 1
                  }
                } else if (type === 'right') {
                  edge['edgeType'] = 'right'
                  edge['style'] = {
                    opacity: 1
                  }
                }

                centerNodeEdges.push(edge)
                this.graph.addItem('edge', edge)
              }
            })

          }

          if (type === 'left') { // 左侧
            this.leftCenterNodeEdges = centerNodeEdges
          } else {
            this.rightCenterNodeEdges = centerNodeEdges
          }
        })
      } else {
        let edges = this.graph.getEdges()
        // 关闭的时候移除该节点上的所有连线
        let cedges = []
        edges.forEach(v => {
          let mod = v.getModel()
          if (mod.target === code) {
            cedges.push(v)
          }
        })
        cedges.forEach(v => {
          this.graph.removeItem(v)
        })

        let isSelected = leafNodes.filter(item => item.selected === true)
        if (isSelected.length > 0) {
          leafNodes = isSelected[0]['lowerIndustry']
          let comparedCodes = []
          leafNodes.forEach(v => {
            comparedCodes.push(v.code)
          })
          this.centerNodes.forEach(v => {
            this.getLeafChildNodeRelation(v, comparedCodes, type)
          })
        }

      }
      
    },
    // 展开/收起 combo
    toggleComboFunc() {
      // 如果选中中间节点子节点则重置样式
      if (Object.keys(this.curCenterChildNode).length > 0) {
        this.graph.setItemState(this.curCenterChildNode, 'selected', false)
        this.curCenterChildNode = {}
      }

      let combo = this.graph.findById('centerCombo')
      let nodes = combo.getNodes()
      nodes.reverse()

      if (this.toggleCombo) {
        this.toggleCombo = false
        nodes.forEach((v, i) => {
          this.graph.updateItem(v, {
            y: this.scrollHeight / 2 - 16
          })
        })

        this.graph.updateCombo(combo)

      } else {
        this.toggleCombo = true
        let posY = nodes[0].getBBox().height + 8
        let comboH = nodes.length * 32 + (nodes.length - 1) * 8
        nodes.forEach((v, i) => {
          this.graph.updateItem(v, {
            y: this.scrollHeight / 2 - 40 - comboH / 2  + posY,
          })
          posY += v.getBBox().height + 8
        })
        
        this.graph.updateCombo(combo)
      }
    },
    // 中心节点子节点点击展示样式
    centerChildNodeStyle(code) {
      let node = this.graph.findById(code)

      let curCenterChildNodeModel = {}
      if (Object.keys(this.curCenterChildNode).length > 0) {
        curCenterChildNodeModel = this.curCenterChildNode.getModel()
      }

      let edges = this.graph.getEdges()
      let comboEdges = edges.filter(item => item.getModel().target === 'centerCombo')
      
      if (code !== curCenterChildNodeModel.code) {
        this.curCenterChildNode = node
        this.centerNodes.forEach(v => {
          if (v.code === code) {
            this.graph.setItemState(node, 'selected', true)
          } 
          else {
            let item = this.graph.findById(v.id)
            this.graph.setItemState(item, 'selected', false)
          }
        })
        comboEdges.forEach(v => {
          this.graph.updateItem(v, {
            style: {
              opacity: '.2'
            }
          })
        })
      } else {
        this.curCenterChildNode = {}
        this.graph.setItemState(node, 'selected', false)
        let isLeftSelected = this.leftLeafNodes[0].filter(item => item.selected === true)
        let isRightSelected = []// this.rightLeafNodes[0].filter(item => item.selected === true)
        if (isLeftSelected.length <= 0 && isRightSelected.length <= 0) {
          comboEdges.forEach(v => {
            this.graph.updateItem(v, {
              style: {
                opacity: '1'
              }
            })
          })
        }
      }
    },
    // 重绘
    toPaint() {
      // 遍历节点实例，将所有节点提前
      if (this.graph.cfg) {
        const nodes = this.graph.getNodes()
        nodes.forEach(v => {
          v.toFront()
        })
        // 更改层级后需要重新绘制图
        this.graph.paint()
      }
    },
    // 更新节点位置和边位置
    refreshPos() {
      let refreshPos = null
      let timer = 0
      let speed = 50
      refreshPos = setInterval(() => {
        if (timer >= 500) {
          clearInterval(refreshPos)
        }
        try {
          this.graph.refreshPositions()
          this.toPaint()
        } catch (error) {
        }
        
        timer += 50
      }, speed)
    },
    // 对象数组去重，并合并节点的多个parent
    distinct(data) {
      let keysArr = []
      data.forEach(v => {
        keysArr.push(v.code)
      })
      keysArr = new Set(keysArr)

      let newData = []
      keysArr.forEach(v => {
        let arr = data.filter(item => item.code === v)
        if (arr.length > 1) {
          let parent = []
          arr.forEach(b => {
            parent.push(b.parent[0])
          })
          arr[0].parent = parent
        }
        newData.push(arr[0])
      })
      return newData
    },
    // 重置
    resetChart(data) {
      if (this.graph) {
        this.graph.destroy()
      }
      // 中心节点
      this.centerNode = {}
      // 当前中心节点子节点
      this.curCenterChildNode = {}
      // 中心节点组
      this.centerNodes = []
      // 左侧叶子节点连线
      this.leftLeafEdges = []
      // 左侧叶子节点与中心子节点的连线
      this.leftCenterNodeEdges = []
      // 右侧叶子节点连线
      this.rightLeafEdges  = []
      // 右侧叶子节点与中心子节点的连线
      this.rightCenterNodeEdges = []
      this.getAllData(data)
    }
  },
  watch: {
    data: {
      deep: true,
      handler() {
        // this.resetChart(this.data)
      }
    },
    dblData() {
      this.resetChart(this.dblData)
    }
  },
  mounted() {
    this.init()
  }
}
</script>

<style lang="scss" scoped>
#container {
  width: 100%;
  height: 500px;
  // background-color: #eee;
}
#minimap {
  // background-color: #efefef;
}
</style>